/* omega copyright (c) 1987,1988,1989 by Laurence Raphael Brothers */
/* gen2.c */
/* level generator functions */

#include "glob.h"



/* For each level, there should be one stairway going up and one down. 
fromlevel determines whether the player is placed on the up or the down
staircase. The aux value is currently unused elsewhere, but is set 
to the destination level. */

void make_stairs(fromlevel)
int fromlevel;
{
  int i,j;
  /* no stairway out of astral */
  if (Current_Environment != E_ASTRAL) {
    findspace(&i,&j,-1);
    Level->site[i][j].locchar = STAIRS_UP;
    Level->site[i][j].aux = Level->depth-1;
    lset(i,j,STOPS);
    if (fromlevel >= 0 && fromlevel < Level->depth) { 
      Player.x = i;
      Player.y = j;
    }
  }
  if (Level->depth < MaxDungeonLevels) {
    findspace(&i,&j,-1);
    Level->site[i][j].locchar = STAIRS_DOWN;
    Level->site[i][j].aux = Level->depth+1;
    lset(i,j,STOPS);
    if (fromlevel > Level->depth) { 
      Player.x = i;
      Player.y = j;
    }
  }
}





/* tactical map generating functions */


void make_country_screen(terrain)
short terrain;
{
  int i,j;
  TempLevel = Level;
  if (ok_to_free(TempLevel)) {
#ifndef SAVE_LEVELS
    free_level(TempLevel);
#endif
    TempLevel = NULL;
  }
#ifndef SAVE_LEVELS
  Level = ((plv) checkmalloc(sizeof(levtype)));
#else
  msdos_changelevel(TempLevel,0,-1);
  Level = &TheLevel;
#endif
  clear_level(Level);
  Level->environment = E_TACTICAL_MAP;
  Level->generated = TRUE;
  switch(terrain) {
  case FOREST: make_forest(); break;
  case JUNGLE: make_jungle(); break;
  case SWAMP: make_swamp(); break;
  case RIVER: make_river(); break;
  case MOUNTAINS: case PASS: make_mountains(); break;
  case ROAD: make_road(); break;
  default: make_plains(); break;
  }
  if (nighttime()) {
    print3("Night's gloom shrouds your sight.");    
    for(i=0;i<WIDTH;i++)
      for(j=0;j<LENGTH;j++) {
	Level->site[i][j].showchar = SPACE;    
	Level->site[i][j].lstatus = 0;
      }
  }
}

void make_general_map(terrain)
char *terrain;
{
  int i, j;
  int size = strlen(terrain);
  char curr;

  for (i=0;i<WIDTH;i++)
    for (j=0;j<LENGTH;j++) {
      if ((i == 0 && j == 0) || !random_range(5))
	curr = terrain[random_range(size)];
      else if (j == 0 || (random_range(2) && i > 0))
	curr = Level->site[i - 1][j].locchar&0xff;
      else
	curr = Level->site[i][j - 1].locchar&0xff;
      switch (curr) {
	case (FLOOR&0xff):
	  Level->site[i][j].locchar = Level->site[i][j].showchar = FLOOR;
	  Level->site[i][j].p_locf = L_NO_OP;
	  break;
	case (HEDGE&0xff):
	  Level->site[i][j].locchar = Level->site[i][j].showchar = HEDGE;
	  Level->site[i][j].p_locf = L_HEDGE;
	  break;
	case (WATER&0xff):
	  Level->site[i][j].locchar = Level->site[i][j].showchar = WATER;
	  Level->site[i][j].p_locf = L_WATER;
	  break;
	case (RUBBLE&0xff):
	  Level->site[i][j].locchar = Level->site[i][j].showchar = RUBBLE;
	  Level->site[i][j].p_locf = L_RUBBLE;
	  break;
      }
      Level->site[i][j].lstatus = SEEN+LIT;
      Level->site[i][j].roomnumber = RS_COUNTRYSIDE;
      if ((i == 0) || (j == 0) || (i == WIDTH-1) || (j == LENGTH-1))
	Level->site[i][j].p_locf = L_TACTICAL_EXIT;
    }
}

void make_plains()
{
  make_general_map(".");
}

void make_road()
{
  int x, y;
  make_general_map("\"\"~4....");
  for (x = WIDTH/2 - 3; x <= WIDTH/2 + 3; x++)
    for (y = 0; y < LENGTH; y++) {
      Level->site[x][y].locchar = Level->site[x][y].showchar = FLOOR;
      if (y != 0 && y != LENGTH - 1)
	Level->site[x][y].p_locf = L_NO_OP;
    }
}



void make_forest()
{
  make_general_map("\".");
  straggle_corridor(0,random_range(LENGTH),WIDTH,random_range(LENGTH),
    WATER,RS_COUNTRYSIDE);
}


void make_jungle()
{
  make_general_map("\"\".");
}


void make_river()
{
  int i,y,y1;
  make_general_map("\".......");
  y = random_range(LENGTH);
  y1 = random_range(LENGTH);
  straggle_corridor(0,y,WIDTH,y1,WATER,RS_COUNTRYSIDE);
  for(i=0;i<7;i++) {
    if (y > LENGTH/2) y--;
    else y++;
    if (y1 > LENGTH/2) y1--;
    else y1++;
    straggle_corridor(0,y,WIDTH,y1,WATER,RS_COUNTRYSIDE);
  }
}


void make_mountains()
{
  int i,x,y,x1,y1;
  make_general_map("4...");
  x = 0;
  y = random_range(LENGTH);
  x1 = WIDTH;
  y1 = random_range(LENGTH);
  straggle_corridor(x,y,x1,y1,WATER,RS_COUNTRYSIDE);
  for(i=0;i<7;i++) {
    x = random_range(WIDTH); 
    x1 = random_range(WIDTH);
    y = 0;
    y1 = LENGTH;
    straggle_corridor(x,y,x1,y1,WATER,RS_COUNTRYSIDE);
  }
}



void make_swamp()
{
  make_general_map("~~\".");
}






/* builds a room. Then, for each successive room, sends off at least one
corridor which is guaranteed to connect up to another room, thus guaranteeing
fully connected level. */

void room_level()
{
  int i,fx,fy,tx,ty,t,l,e;
  char rsi;

  Level->numrooms = random_range(8)+9;

  do {
    t = random_range(LENGTH-10)+1;
    l = random_range(WIDTH-10)+1;
    e = 4+random_range(5);
  } while ((Level->site[l][t].roomnumber != RS_WALLSPACE) ||
	   (Level->site[l+e][t].roomnumber != RS_WALLSPACE) ||
	   (Level->site[l][t+e].roomnumber != RS_WALLSPACE) ||
	   (Level->site[l+e][t+e].roomnumber != RS_WALLSPACE));
  if (Current_Dungeon == E_SEWERS) {
    if (random_range(2)) rsi = ROOMBASE+25;
    else rsi = ROOMBASE+random_range(NUMROOMNAMES);
  }
  else rsi = ROOMBASE+random_range(NUMROOMNAMES);
  build_room(l,t,e,rsi,1);


  for (i=2;i<=Level->numrooms;i++) {
    do {
      t = random_range(LENGTH-10)+1;
      l = random_range(WIDTH-10)+1;
      e = 4+random_range(5);
    } while ((Level->site[l][t].roomnumber != RS_WALLSPACE) ||
	     (Level->site[l+e][t].roomnumber != RS_WALLSPACE) ||
	     (Level->site[l][t+e].roomnumber != RS_WALLSPACE) ||
	     (Level->site[l+e][t+e].roomnumber != RS_WALLSPACE));
    if (Current_Dungeon == E_SEWERS) {
      if (random_range(2)) rsi = ROOMBASE+25;
      else rsi = ROOMBASE+random_range(NUMROOMNAMES);
    }
    else rsi = ROOMBASE+random_range(NUMROOMNAMES);
    build_room(l,t,e,rsi,i);
    

    /* corridor which is guaranteed to connect */
    findspace(&tx,&ty,i);

    /* figure out where to start corridor from */
    if ((ty <= t) && (tx <= l+e)) {
      fx = l+1+random_range(e-1);
      fy = t;
    }
    else if ((tx >= l+e) && (ty <= t+e)) {
      fx = l+e;
      fy = t+1+random_range(e-1);
    }
    else if ((ty >= t+e) && (tx >= l)) {
      fx = l+1+random_range(e-1);
      fy = t+e;
    }
    else {
      fx = l;
      fy = t+1+random_range(e-1);
    }

    room_corridor(fx,fy,tx,ty,i);


    /* corridor which may not go anywhere */
    if (random_range(2)) {
      findspace(&tx,&ty,i);
      if ((ty <= t) && (tx <= l+e)) {
	fx = l+1+random_range(e-1);
	fy = t;
      }
      else if ((tx >= l+e) && (ty <= t+e)) {
	fx = l+e;
	fy = t+1+random_range(e-1);
      }
      else if ((ty >= t+e) && (tx >= l)) {
	fx = l+1+random_range(e-1);
	fy = t+e;
      }
      else {
	fx = l;
	fy = t+1+random_range(e-1);
      }
      room_corridor(fx,fy,tx,ty,i);
    }
  }

  if (Current_Dungeon == E_SEWERS) {
    if (Level->depth == SEWERLEVELS) {
      findspace(&tx,&ty,-1);
      Level->mlist = ((pml) checkmalloc(sizeof(mltype)));
      Level->mlist->next = NULL;
      Level->mlist->m = 
	Level->site[tx][ty].creature = 
	  ((pmt) make_creature(ML7+5)); /* The Great Wyrm */
      Level->mlist->m->x = tx;
      Level->mlist->m->y = ty;
    }
  }
  else if (Current_Environment == E_CASTLE) {
    if (Level->depth == CASTLELEVELS) {
      findspace(&tx,&ty,-1);
      Level->site[tx][ty].locchar = STAIRS_DOWN;
      Level->site[tx][ty].p_locf = L_ENTER_COURT;
    }
  }
  else if (Current_Environment == E_VOLCANO) {
    if (Level->depth == VOLCANOLEVELS && !gamestatusp(COMPLETED_VOLCANO)) {
      findspace(&tx,&ty,-1);
      Level->mlist = ((pml) checkmalloc(sizeof(mltype)));
      Level->mlist->next = NULL;
      Level->mlist->m = 
	Level->site[tx][ty].creature = 
	  ((pmt) make_creature(ML10+4)); /* The demon emp */
      Level->mlist->m->x = tx;
      Level->mlist->m->y = ty;
    }
  }
}



/* goes from f to t unless it hits a site which is not a wall and doesn't
   have buildaux field == baux */
void room_corridor(fx,fy,tx,ty,baux)
int fx,fy,tx,ty,baux;
{
  int dx,dy,continuing = TRUE;

  dx = sign(tx-fx);
  dy = sign(ty-fy);

  makedoor(fx,fy);

  fx+=dx;
  fy+=dy;

  while(continuing) {
    Level->site[fx][fy].locchar = FLOOR;
    Level->site[fx][fy].roomnumber = RS_CORRIDOR;
    Level->site[fx][fy].buildaux = baux;
    dx = sign(tx-fx);
    dy = sign(ty-fy);
    if ((dx != 0) && (dy != 0)) {
      if (random_range(2)) dx = 0;
      else if (random_range(2)) dy = 0;
    }
    fx+=dx;
    fy+=dy;
    continuing = (((fx != tx) || (fy != ty)) &&
		  ((Level->site[fx][fy].buildaux == 0) ||
		   (Level->site[fx][fy].buildaux == baux)));
  }
  makedoor(fx,fy);
}





void maze_level()
{
  int i,j,tx,ty,mid;
  char rsi;
  if (Current_Environment == E_ASTRAL)
    switch(Level->depth){
    case 1: rsi = RS_EARTHPLANE; break;
    case 2: rsi = RS_AIRPLANE; break;
    case 3: rsi = RS_WATERPLANE; break;
    case 4: rsi = RS_FIREPLANE; break;
    case 5: rsi = RS_HIGHASTRAL; break;
    }
  else rsi = RS_VOLCANO;
  maze_corridor(random_range(WIDTH-1)+1,
		random_range(LENGTH-1)+1,
		random_range(WIDTH-1)+1,
		random_range(LENGTH-1)+1,
		rsi,0);
  if (Current_Dungeon == E_ASTRAL) {
    for(i=0;i<WIDTH;i++) 
      for(j=0;j<LENGTH;j++) 
	if (Level->site[i][j].locchar == WALL)
	  switch(Level->depth){
	  case 1: Level->site[i][j].aux = 500; break;
	  case 2: 
	    Level->site[i][j].locchar = WHIRLWIND;
	    Level->site[i][j].p_locf = L_WHIRLWIND;
	    break;
	  case 3: 
	    Level->site[i][j].locchar = WATER;
	    Level->site[i][j].p_locf = L_WATER;
	    break;
	  case 4:
	    Level->site[i][j].locchar = FIRE;
	    Level->site[i][j].p_locf = L_FIRE;
	    break;
	  case 5: 
	    Level->site[i][j].locchar = ABYSS;
	    Level->site[i][j].p_locf = L_ABYSS;
	    break;
	  }
    switch(Level->depth) {
    case 1: mid = ML10+5; break; /* Elemental Lord of Earth */
    case 2: mid = ML10+6; break; /* Elemental Lord of Air */
    case 3: mid = ML10+7; break; /* Elemental Lord of Water */
    case 4: mid = ML10+8; break; /* Elemental Lord of Fire */
    case 5: mid = ML10+9; break; /* Elemental Master */
    }
    if (Level->depth == 5) {
      findspace(&tx,&ty,-1);
      Level->site[tx][ty].p_locf = L_ENTER_CIRCLE;
      Level->site[tx][ty].locchar = STAIRS_DOWN;
    }
    if (! gamestatusp(COMPLETED_ASTRAL)) {
      findspace(&tx,&ty,-1);
      Level->mlist = ((pml) checkmalloc(sizeof(mltype)));
      Level->mlist->next = NULL;
      Level->mlist->m = 
	Level->site[tx][ty].creature = 
	  ((pmt) make_creature(mid)); 
      Level->mlist->m->x = tx;
      Level->mlist->m->y = ty;
    }
  }
  else if (Current_Environment == E_VOLCANO) {
    if (Level->depth == VOLCANOLEVELS && !gamestatusp(COMPLETED_VOLCANO)) {
      findspace(&tx,&ty,-1);
      Level->mlist = ((pml) checkmalloc(sizeof(mltype)));
      Level->mlist->next = NULL;
      Level->mlist->m = 
	Level->site[tx][ty].creature = 
	  ((pmt) make_creature(ML10+4)); /* The demon emp */
      Level->mlist->m->x = tx;
      Level->mlist->m->y = ty;
    }
  }
}


/* keep drawing corridors recursively for 2^5 endpoints */
void maze_corridor(fx,fy,tx,ty,rsi,num)
int fx,fy,tx,ty;
char rsi,num;
{
  if (num < 6) {
    straggle_corridor(fx,fy,tx,ty,FLOOR,rsi);
    maze_corridor(tx,ty,
		  random_range(WIDTH-1)+1,
		  random_range(LENGTH-1)+1,
		  rsi,num+1);
    
  }
}





